package velox.jcr.mapper;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import javax.jcr.RepositoryException;

import org.springmodules.jcr.SessionFactoryUtils;



public class LazyList<T> extends AbstractPersistentCollection implements List<T> {
	private boolean loaded;
	private Loader<List<String>> nodeLoader;
	private List<T> entries;
	private Class<?> type;
	private String uuid;
	 
	public LazyList(String uuid, Loader<List<String>> nodeLoader, Class<?> type) {
		this.uuid = uuid;
		this.nodeLoader = nodeLoader;
		this.loaded = false;
		this.type = type;
	}

	@SuppressWarnings("unchecked")
	public void load() {
		try {
			this.entries = new ArrayList<T>();
			for (String id : nodeLoader.load(this.uuid)) {
				try {
					this.entries.add((T) UnitOfWorkHolder.get().getMapperManager().get(new NodeRef(id), type));
				} catch (AccessDeniedException ade) {
					// Ignore these
				}
			}
			this.loaded = true;
		} catch (RepositoryException e) {
			throw SessionFactoryUtils.translateException(e);
		}
	}
	
	@Override
	public boolean isLoaded() {
		return this.loaded;
	}
	
	public boolean add(T t) {
		if (! loaded) load();
		registerAdd(t);
		return entries.add(t);
	}

	public void add(int pos, T t) {
		if (! loaded) load();
		registerAdd(t);
		entries.add(pos, t);
	}

	public boolean addAll(Collection<? extends T> c) {
		if (! loaded) load();
		for (T t : c) {
			registerAdd(t);
		}
		return entries.addAll(c);
	}

	public boolean addAll(int pos, Collection<? extends T> c) {
		if (! loaded) load();
		for (T t : c) {
			registerAdd(t);
		}
		return entries.addAll(pos, c);
	}

	public void clear() {
		if (! loaded) load();
		for (T t : entries) {
			registerRemove(t);
		}
		entries.clear();
	}

	public boolean contains(Object o) {
		if (! loaded) load();
		return entries.contains(o);
	}

	public boolean containsAll(Collection<?> c) {
		if (! loaded) load();
		return entries.contains(c);
	}

	@SuppressWarnings("unchecked")
	public T get(int p) {
		if (! loaded) load();
		return entries.get(p);
	}

	public int indexOf(Object o) {
		if (! loaded) load();
		return entries.indexOf(o);
	}

	public boolean isEmpty() {
		if (! loaded) load();
		return entries.isEmpty();
	}

	public Iterator<T> iterator() {
		if (! loaded) load();
		return entries.iterator();
	}

	public int lastIndexOf(Object o) {
		if (! loaded) load();
		return entries.lastIndexOf(o);
	}

	public ListIterator<T> listIterator() {
		if (! loaded) load();
		return entries.listIterator();
	}

	public ListIterator<T> listIterator(int index) {
		if (! loaded) load();
		return entries.listIterator(index);
	}

	public boolean remove(Object o) {
		if (! loaded) load();
		registerRemove(o);
		return entries.remove(o);
	}

	public T remove(int index) {
		if (! loaded) load();
		registerRemove(entries.get(index));
		return entries.remove(index);
	}

	public boolean removeAll(Collection<?> c) {
		if (! loaded) load();
		for (Object o : c) {
			registerRemove(o);
		}
		return entries.removeAll(c);
	}

	public boolean retainAll(Collection<?> c) {
		if (! loaded) load();
		for (Object o : entries) {
			if (! c.contains(o)) {
				registerRemove(o);
			}
		}
		return entries.retainAll(c);
	}

	public T set(int index, T element) {
		if (! loaded) load();
		registerRemove(entries.get(index));
		registerAdd(element);
		return entries.set(index, element);
	}

	public int size() {
		if (! loaded) load();
		return entries.size();
	}

	public List<T> subList(int fromIndex, int toIndex) {
		if (! loaded) load();
		return entries.subList(fromIndex, toIndex);
	}

	public Object[] toArray() {
		if (! loaded) load();
		return entries.toArray();
	}

	public <U> U[] toArray(U[] a) {
		if (! loaded) load();
		return entries.toArray(a);
	}
}
